import axios from "axios";
import { useUserStore } from "@/stores/index";
import router from "@/router";
import { ElMessage, ElMessageBox } from "element-plus";
import { v4 as uuidv4 } from "uuid";
import { getAccessToken, getRefreshToken, SET_TOKEN } from "@/utils/token";
const baseURL = "http://192.168.0.96:9999";

import { refreshToken } from "@/api/user";
// 请求队列
let requestList = [];
// 是否正在刷新中
let isRefreshToken = false;
export let isRelogin = {
  show: false,
};

const service = axios.create({
  // axios中请求配置有baseURL选项，表示请求URL公共部分
  baseURL,
  // 超时
  timeout: 120000,
  // 禁用 Cookie 等信息
  withCredentials: false,
});

service.interceptors.request.use(
  (config) => {
    console.log(config);
    const isToken = (config.headers || {}).isToken === false;
    // TODO 2. 携带token
    if (getAccessToken() && !isToken) {
      config.headers["Authorization"] = getAccessToken();
    }
    config.headers["x-request-id"] = `request:${Math.floor(
      Date.now() / 1000
    )}-${uuidv4().substring(0, 8)}`;

    // get请求映射params参数 （特殊处理 GET 请求参数:）
    // 1. 支持后端框架的数组参数格式 array[0]=1
    // 2. 支持多级对象的参数格式 user[address][city]=Beijing
    // 3. 防止已有 URL 参数被重复添加
    if (
      config.method === "get" &&
      config.params &&
      Object.keys(config.params).length > 0
    ) {
      if (config.url.includes("?")) {
        // 当已经包含?时说明已经拼凑URL 二次请求不在生成URL
        config.params = {};
        return config;
      }
      let url = config.url + "?";
      for (const propName of Object.keys(config.params)) {
        const value = config.params[propName];
        const part = encodeURIComponent(propName) + "=";
        if (value !== null && typeof value !== "undefined") {
          if (typeof value === "object") {
            for (const key of Object.keys(value)) {
              let params = propName + "[" + key + "]";
              const subPart = encodeURIComponent(params) + "=";
              url += subPart + encodeURIComponent(value[key]) + "&";
            }
          } else {
            url += part + encodeURIComponent(value) + "&";
          }
        }
      }
      url = url.slice(0, -1);
      config.params = {};
      config.url = url;
    }
    return config;
  },
  (err) => Promise.reject(err)
);

service.interceptors.response.use(
  (res) => {
    // TODO 3. 处理业务失败
    // TODO 4. 摘取核心响应数据

    if (res.data.code === 0) {
      return res.data;
    }
    ElMessage({ message: res.data.message || "服务异常", type: "error" });
    return Promise.reject(res.data);
  },
  async (err) => {
    let msg = err.response.data.message;
    if (err.response.status === 401) {
      // 如果未认证，并且未进行刷新令牌，说明可能是访问令牌过期了
      if (!isRefreshToken) {
        isRefreshToken = true;
        // 1. 如果获取不到刷新令牌，则只能执行登出操作
        if (!getRefreshToken()) {
          return handleAuthorized();
        }
        // 2. 进行刷新访问令牌
        try {
          const refreshTokenRes = await refreshToken();
          // 2.1 刷新成功，则回放队列的请求 + 当前请求
          SET_TOKEN(refreshTokenRes.result);
          requestList.forEach((cb) => cb());
          console.log(refreshTokenRes);
          console.log(err);

          return service(err.config);
        } catch (e) {
          console.log(e);
          // 为什么需要 catch 异常呢？刷新失败时，请求因为 Promise.reject 触发异常。
          // 2.2 刷新失败，只回放队列的请求
          requestList.forEach((cb) => cb());
          // 提示是否要登出。即不回放当前请求！不然会形成递归
          return handleAuthorized();
        } finally {
          requestList = [];
          isRefreshToken = false;
        }
      } else {
        // 添加到队列，等待刷新获取到新的令牌
        return new Promise((resolve) => {
          requestList.push(() => {
            err.config.headers["Authorization"] = getAccessToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
            resolve(service(err.config));
          });
        });
      }
    } else {
      if (msg == "无效的刷新令牌") {
        // hard coding：忽略这个提示，直接登出
      } else {
        ElMessage({
          message: msg || "服务异常",
          type: "error",
        });
      }

      return Promise.reject(msg);
    }
  }
);

function handleAuthorized() {
  const userStore = useUserStore();
  if (!isRelogin.show) {
    isRelogin.show = true;
    ElMessageBox.confirm(
      "登录状态已过期，您可以继续留在该页面，或者重新登录",
      "系统提示",
      {
        confirmButtonText: "重新登录",
        cancelButtonText: "取消",
        type: "warning",
      }
    )
      .then(async () => {
        isRelogin.show = false;
        await userStore.userlogout();
        router.push("/login");
      })
      .catch(() => {
        isRelogin.show = false;
      });
  }
  return Promise.reject("无效的会话，或者会话已过期，请重新登录。");
}
export default service;
export { baseURL };
